#!/usr/bin/env python3
"""
真实数据回测脚本
使用OKX交易所的真实K线数据进行回测
"""

import asyncio
import sys
import pandas as pd
import numpy as np
from pathlib import Path
from datetime import datetime, timedelta
from typing import Dict, List
import json

# 添加项目根目录到Python路径
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))

from xcquant.core import unified_core, unified_logger
from xcquant.exchanges.okx_exchange import OKXExchange


class RealDataBacktestRunner:
    """真实数据回测运行器"""
    
    def __init__(self):
        self.logger = unified_logger.get_logger(__name__)
        self.results_dir = Path("./real_backtest_results")
        self.results_dir.mkdir(exist_ok=True)
        
        # 初始化OKX交易所（不需要API密钥获取公开市场数据）
        self.exchange = OKXExchange({
            'api_key': '',
            'secret_key': '',
            'passphrase': '',
            'sandbox': False  # 使用生产环境获取真实数据
        })
        
    def get_real_kline_data(self, symbol: str, period: str, limit: int = 100) -> pd.DataFrame:
        """获取真实K线数据"""
        self.logger.info(f"正在从OKX获取 {symbol} 的真实K线数据，周期: {period}, 数量: {limit}")
        
        try:
            # 获取K线数据
            klines = self.exchange.get_kline(symbol, period, limit)
            
            if not klines:
                self.logger.error(f"未能获取到 {symbol} 的K线数据")
                return pd.DataFrame()
            
            # 转换为DataFrame
            df = pd.DataFrame(klines)
            
            # 转换时间戳
            df['datetime'] = pd.to_datetime(df['timestamp'], unit='ms')
            df['timestamp'] = df['timestamp'] / 1000  # 转换为秒
            
            # 设置索引
            df.set_index('datetime', inplace=True)
            
            # 确保数据类型正确
            for col in ['open', 'high', 'low', 'close', 'volume']:
                df[col] = pd.to_numeric(df[col], errors='coerce')
            
            self.logger.info(f"成功获取 {len(df)} 条真实K线数据")
            self.logger.info(f"数据时间范围: {df.index.min()} 到 {df.index.max()}")
            self.logger.info(f"价格范围: {df['close'].min():.2f} - {df['close'].max():.2f}")
            
            return df
            
        except Exception as e:
            self.logger.error(f"获取真实K线数据失败: {e}")
            return pd.DataFrame()
    
    def run_grid_strategy_backtest(self, data: pd.DataFrame, symbol: str) -> Dict:
        """运行网格策略回测"""
        self.logger.info("开始运行网格策略回测...")
        
        if data.empty:
            self.logger.error("数据为空，无法进行回测")
            return {}
        
        # 回测参数
        initial_balance = 10000.0  # 初始资金 10000 USDT
        commission_rate = 0.001    # 手续费率 0.1%
        grid_count = 10           # 网格数量
        price_range = 0.05        # 价格范围 5%
        
        # 计算网格参数
        min_price = data['close'].min()
        max_price = data['close'].max()
        current_price = data['close'].iloc[-1]
        
        # 基于当前价格设置网格范围
        grid_min = current_price * (1 - price_range)
        grid_max = current_price * (1 + price_range)
        grid_step = (grid_max - grid_min) / grid_count
        
        self.logger.info(f"网格参数: 最低价 {grid_min:.2f}, 最高价 {grid_max:.2f}, 网格间距 {grid_step:.2f}")
        
        # 初始化交易状态
        balance = initial_balance
        position = 0.0  # 持仓数量
        trades = []
        
        # 网格买入价格列表
        buy_levels = [grid_min + i * grid_step for i in range(grid_count)]
        sell_levels = [level + grid_step for level in buy_levels]
        
        # 记录已触发的网格
        triggered_buys = set()
        triggered_sells = set()
        
        # 遍历历史数据进行回测
        for timestamp, row in data.iterrows():
            price = row['close']
            
            # 检查买入信号
            for i, buy_price in enumerate(buy_levels):
                if price <= buy_price and i not in triggered_buys:
                    # 计算买入数量
                    trade_amount = balance * 0.1  # 每次使用10%的资金
                    if trade_amount > 10:  # 最小交易金额
                        quantity = trade_amount / price
                        commission = trade_amount * commission_rate
                        
                        if balance >= trade_amount + commission:
                            balance -= (trade_amount + commission)
                            position += quantity
                            triggered_buys.add(i)
                            
                            trades.append({
                                'timestamp': timestamp,
                                'type': 'buy',
                                'price': price,
                                'quantity': quantity,
                                'amount': trade_amount,
                                'commission': commission,
                                'balance': balance,
                                'position': position
                            })
                            
                            self.logger.debug(f"买入: 价格 {price:.2f}, 数量 {quantity:.6f}, 金额 {trade_amount:.2f}")
            
            # 检查卖出信号
            for i, sell_price in enumerate(sell_levels):
                if price >= sell_price and i not in triggered_sells and position > 0:
                    # 计算卖出数量（卖出部分持仓）
                    sell_quantity = position * 0.2  # 每次卖出20%的持仓
                    if sell_quantity * price > 10:  # 最小交易金额
                        trade_amount = sell_quantity * price
                        commission = trade_amount * commission_rate
                        
                        balance += (trade_amount - commission)
                        position -= sell_quantity
                        triggered_sells.add(i)
                        
                        # 重置对应的买入网格
                        if i in triggered_buys:
                            triggered_buys.remove(i)
                        
                        trades.append({
                            'timestamp': timestamp,
                            'type': 'sell',
                            'price': price,
                            'quantity': sell_quantity,
                            'amount': trade_amount,
                            'commission': commission,
                            'balance': balance,
                            'position': position
                        })
                        
                        self.logger.debug(f"卖出: 价格 {price:.2f}, 数量 {sell_quantity:.6f}, 金额 {trade_amount:.2f}")
        
        # 计算最终收益
        final_price = data['close'].iloc[-1]
        final_value = balance + position * final_price
        total_return = (final_value - initial_balance) / initial_balance * 100
        
        # 计算交易统计
        buy_trades = [t for t in trades if t['type'] == 'buy']
        sell_trades = [t for t in trades if t['type'] == 'sell']
        
        # 计算盈利交易
        profitable_trades = 0
        total_profit = 0
        
        for sell_trade in sell_trades:
            # 简化的盈利计算
            avg_buy_price = sum(t['price'] for t in buy_trades) / len(buy_trades) if buy_trades else 0
            if sell_trade['price'] > avg_buy_price:
                profitable_trades += 1
                total_profit += (sell_trade['price'] - avg_buy_price) * sell_trade['quantity']
        
        win_rate = (profitable_trades / len(sell_trades) * 100) if sell_trades else 0
        
        results = {
            'symbol': symbol,
            'initial_balance': initial_balance,
            'final_balance': balance,
            'final_position': position,
            'final_position_value': position * final_price,
            'final_total_value': final_value,
            'total_return_pct': total_return,
            'total_trades': len(trades),
            'buy_trades': len(buy_trades),
            'sell_trades': len(sell_trades),
            'win_rate': win_rate,
            'total_commission': sum(t['commission'] for t in trades),
            'trades': trades,
            'data_points': len(data),
            'backtest_period': f"{data.index.min()} 到 {data.index.max()}",
            'price_range': f"{data['close'].min():.2f} - {data['close'].max():.2f}"
        }
        
        self.logger.info(f"回测完成: 总收益率 {total_return:.2f}%, 交易次数 {len(trades)}, 胜率 {win_rate:.2f}%")
        
        return results
    
    def save_results(self, results: Dict, symbol: str, period: str):
        """保存回测结果"""
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        
        # 保存详细结果
        results_file = self.results_dir / f"real_backtest_{symbol}_{period}_{timestamp}.json"
        with open(results_file, 'w', encoding='utf-8') as f:
            # 处理不能序列化的对象
            serializable_results = results.copy()
            if 'trades' in serializable_results:
                for trade in serializable_results['trades']:
                    if 'timestamp' in trade:
                        trade['timestamp'] = str(trade['timestamp'])
            
            json.dump(serializable_results, f, indent=2, ensure_ascii=False)
        
        # 生成报告
        report_file = self.results_dir / f"real_backtest_report_{symbol}_{period}_{timestamp}.txt"
        with open(report_file, 'w', encoding='utf-8') as f:
            f.write(f"真实数据回测报告\n")
            f.write(f"=" * 50 + "\n")
            f.write(f"交易对: {results['symbol']}\n")
            f.write(f"回测时间: {timestamp}\n")
            f.write(f"数据周期: {period}\n")
            f.write(f"回测期间: {results['backtest_period']}\n")
            f.write(f"数据点数: {results['data_points']}\n")
            f.write(f"价格范围: {results['price_range']}\n")
            f.write(f"\n回测结果:\n")
            f.write(f"初始资金: {results['initial_balance']:.2f} USDT\n")
            f.write(f"最终资金: {results['final_balance']:.2f} USDT\n")
            f.write(f"最终持仓: {results['final_position']:.6f} {symbol.split('-')[0]}\n")
            f.write(f"持仓价值: {results['final_position_value']:.2f} USDT\n")
            f.write(f"总资产价值: {results['final_total_value']:.2f} USDT\n")
            f.write(f"总收益率: {results['total_return_pct']:.2f}%\n")
            f.write(f"总交易次数: {results['total_trades']}\n")
            f.write(f"买入次数: {results['buy_trades']}\n")
            f.write(f"卖出次数: {results['sell_trades']}\n")
            f.write(f"胜率: {results['win_rate']:.2f}%\n")
            f.write(f"总手续费: {results['total_commission']:.2f} USDT\n")
            
            # 显示最近的交易记录
            f.write(f"\n最近10笔交易:\n")
            recent_trades = results['trades'][-10:] if results['trades'] else []
            for i, trade in enumerate(recent_trades, 1):
                f.write(f"{i:2d}. {trade['timestamp']} | {trade['type'].upper():4s} | "
                       f"价格: {trade['price']:8.2f} | 数量: {trade['quantity']:10.6f} | "
                       f"金额: {trade['amount']:8.2f} | 手续费: {trade['commission']:6.2f}\n")
        
        self.logger.info(f"回测结果已保存到: {results_file}")
        self.logger.info(f"回测报告已保存到: {report_file}")
    
    async def run_real_backtest(self, symbol: str = "BTC-USDT", period: str = "1H", limit: int = 200):
        """运行真实数据回测"""
        self.logger.info(f"开始真实数据回测: {symbol}, 周期: {period}, 数据量: {limit}")
        
        # 获取真实数据
        data = self.get_real_kline_data(symbol, period, limit)
        
        if data.empty:
            self.logger.error("无法获取真实数据，回测终止")
            return
        
        # 运行回测
        results = self.run_grid_strategy_backtest(data, symbol)
        
        if results:
            # 保存结果
            self.save_results(results, symbol, period)
            
            # 显示摘要
            self.logger.info("=" * 60)
            self.logger.info("真实数据回测完成!")
            self.logger.info(f"交易对: {symbol}")
            self.logger.info(f"数据周期: {period}")
            self.logger.info(f"数据量: {len(data)} 条")
            self.logger.info(f"总收益率: {results['total_return_pct']:.2f}%")
            self.logger.info(f"总交易次数: {results['total_trades']}")
            self.logger.info(f"胜率: {results['win_rate']:.2f}%")
            self.logger.info("=" * 60)


async def main():
    """主函数"""
    runner = RealDataBacktestRunner()
    
    # 运行不同周期的回测
    test_cases = [
        ("BTC-USDT", "1H", 168),   # 1小时K线，7天数据
        ("BTC-USDT", "4H", 180),   # 4小时K线，30天数据
        ("BTC-USDT", "1D", 90),    # 日K线，90天数据
        ("ETH-USDT", "1H", 168),   # ETH 1小时K线
    ]
    
    for symbol, period, limit in test_cases:
        print(f"\n{'='*60}")
        print(f"开始回测: {symbol} - {period} - {limit}条数据")
        print(f"{'='*60}")
        
        await runner.run_real_backtest(symbol, period, limit)
        
        # 等待一下，避免API请求过于频繁
        await asyncio.sleep(2)
    
    print(f"\n{'='*60}")
    print("所有真实数据回测完成!")
    print(f"结果保存在: {runner.results_dir}")
    print(f"{'='*60}")


if __name__ == "__main__":
    asyncio.run(main())